﻿using System;
using System.Collections.Generic;
using System.Net;
using AdAggregator.Parser;
using AdAggregator.Util;
using AdAggregator.Website;
using CsQuery;
using RealEstateAggregator.Models.SearchData;
using log4net;

namespace RealEstateAggregator.Models.Parsers
{
    public class SzybkoPlParser : BaseParser<SzybkoPlSearchData, MyAdvertisement>
    {
        private readonly ILog log = LogManager.GetLogger(typeof(SzybkoPlParser));

        private const int AdsPerPage = 10;
        private readonly Dictionary<string, string> uris = new Dictionary<string, string>
            {
                {"HouseFlat", "http://www.szybko.pl/index.php?nav1=search&type={0}&keywords_desc=true&cities={1}&suburbs={14}&area_min={2}&area_max={3}&estate_type%5B%5D={4}&area={5}&street={15}&rooms_count={6}&price_min={7}&price_max={8}&market={10}&znak={11}&free_buildyear={12}&keywords={9}{13}"
                },
                {"CommercialLandRoom","http://www.szybko.pl/index.php?nav1=search&type={0}&keywords_desc=true&cities={1}&suburbs={8}&{0}_type%5B%5D={2}&area={3}&street={9}&price_min={4}&price_max={5}&keywords={6}{7}"
                }
            };

        protected override String ComposeUri()
        {
            string uri;

            if (SearchData.EstateType == "house" || SearchData.EstateType == "flat")
            {
                string yearBuiltParam;
                string yearBuilt;
                if (String.IsNullOrEmpty(SearchData.YearBuiltMin) && String.IsNullOrEmpty(SearchData.YearBuiltMax))
                {
                    yearBuiltParam = "-1";
                    yearBuilt = "0";
                }
                else if (!String.IsNullOrEmpty(SearchData.YearBuiltMin))
                {
                    yearBuiltParam = "1";
                    yearBuilt = SearchData.YearBuiltMin;
                }
                else
                {
                    yearBuiltParam = "-1";
                    yearBuilt = SearchData.YearBuiltMax;
                }
                uri = String.Format(uris["HouseFlat"], SearchData.AdvertisementType, SearchData.City, SearchData.AreaMin,
                    SearchData.AreaMax, SearchData.EstateType, SearchData.Voivodship, SearchData.RoomCount, SearchData.PriceMin,
                    SearchData.PriceMax, SearchData.Keywords, SearchData.MarketType, yearBuiltParam, yearBuilt,
                    SearchData.OnlyWithPhoto ? "&pictureRequired=1" : "", SearchData.District, SearchData.Street);
            }
            else
            {
                uri = String.Format(uris["CommercialLandRoom"], SearchData.EstateType, SearchData.City, SearchData.SpecialType,
                    SearchData.Voivodship, SearchData.PriceMin, SearchData.PriceMax, SearchData.Keywords,
                    SearchData.OnlyWithPhoto ? "&pictureRequired=1" : "", SearchData.District, SearchData.Street);

                if (SearchData.EstateType == "komercyjne")
                    uri += String.Format("&ktype_sell={0}&ktype_rent={1}", SearchData.AdvertisementType == "sell" ? "1" : "0", SearchData.AdvertisementType == "rent" ? "1" : "0");

                if (SearchData.EstateType != "room")
                    uri += String.Format("&area_min={0}&area_max={1}", SearchData.AreaMin, SearchData.AreaMax);
            }

            if (SearchData.Page > 1)
                uri += "&offset=" + AdsPerPage * (SearchData.Page - 1);

            return uri;
        }

        public override string Name
        {
            get { return "SzybkoPl"; }
        }

        public override IParseResult<MyAdvertisement> Parse(SzybkoPlSearchData searchData, IAdvertisementSource<MyAdvertisement> website)
        {
            if (searchData.RoomCountMin != searchData.RoomCountMax && searchData.RoomCountMax != "0")
            {
                var requestCnt = Int32.Parse(searchData.RoomCountMax) - Int32.Parse(searchData.RoomCountMin) + 1;
                var ads = new List<MyAdvertisement>();
                for (int i = 0; i < requestCnt; i++)
                {
                    searchData.RoomCount = (Int32.Parse(searchData.RoomCountMin) + i).ToString();
                    if (searchData.RoomCount == "0") continue;
                    ads.AddRange(base.Parse(searchData, website).Results);
                }
                return new ParseResult<MyAdvertisement> { Results = ads };
            }
            searchData.RoomCount = int.Parse(searchData.RoomCountMax) > int.Parse(searchData.RoomCountMin) ?
                searchData.RoomCountMax :
                searchData.RoomCountMin;
            return base.Parse(searchData, website);
        }

        protected override IParseResult<MyAdvertisement> ParseResponse(HttpWebResponse response, IAdvertisementSource<MyAdvertisement> website)
        {
            var list = new List<MyAdvertisement>();
            var dom = CQ.Create(response.GetResponseStream());
            var ads = dom["div.listUNIT:not(.ads, .padding0)"];
            foreach (var el in ads)
            {
                var myAd = new MyAdvertisement();
                try
                {
                    var ad = CQ.Create(el);
                    var title = ad["div.div2 a.nagl"];
                    myAd.Link = title.Attr("href");
                    var img = ad["a.preview1 img"];
                    ParseFullAd(title.Attr("href"), myAd);
                    myAd.Title = title.Text();
                    myAd.Photo = img.Length > 0 ? img.Attr("src") : null;
                    myAd.AdSource = Name + ".png";
                    myAd.Source = website;
                    if (SearchData.EstateType == "house" || SearchData.EstateType == "flat")
                    {
                        var roomInfo = ad["p.info1"].Text();
                        if (roomInfo.Contains("pok"))
                        {
                            roomInfo = roomInfo.RemoveFirstAtTheEnd("pok").Trim();
                            myAd.RoomCount = roomInfo.ToNullableInt();
                        }
                        else myAd.RoomCount = null;
                    }
                    else myAd.RoomCount = null;
                    list.Add(myAd);
                }
                catch (Exception ex)
                {
                    log.Debug(String.Format("{0}: exception while parsing [{1}]", GetType().Name, myAd.Link), ex);
                }
            }
            return new ParseResult<MyAdvertisement> { Results = list };
        }

        private void ParseFullAd(string link, MyAdvertisement myAd)
        {
            var innerRequest = WebRequest.Create(link) as HttpWebRequest;
            var innerResponse = innerRequest.GetResponse() as HttpWebResponse;
            var innerDom = CQ.Create(innerResponse.GetResponseStream());
            var locationText = innerDom["h1.szczeg_h1"].Text();
            if (locationText.Length > 0)
            {
                var location = locationText.Substring(locationText.IndexOf(" - ") + 3).Split(',');
                myAd.City = location[0].Trim();
                myAd.Voivodship = location[location.Length - 1].Replace("woj.", "").Trim();
                if (location.Length == 3)
                {
                    myAd.Street = location[1].Trim();
                }
                else if (location.Length == 4)
                {
                    myAd.District = location[1].Trim();
                    myAd.Street = location[2].Trim();
                }
            }
            var year = innerDom["div.szczegoly ul li:contains(rok budowy:)"].Html().Trim();
            if (year.Contains("<strong>"))
                year = year.Substring(year.IndexOf("</strong>") + 9).Trim();
            myAd.YearBuilt = String.IsNullOrEmpty(year) ? null : year.ToNullableInt();
            var price = innerDom["#cena"].Text().RemoveNonDigits();
            myAd.Price = price.ToNullableDecimal();
            string area;
            if (SearchData.EstateType == "room")
            {
                area = innerDom["h2.szczeg_h2"].Text().RemoveFirstAtTheBeginning(":").RemoveFirstAtTheEnd("m").Trim().FormatAsNumberWithSpaces();
            }
            else
            {
                area =
                    innerDom["div.dane"].Find("div")
                                        .Text()
                                        .RemoveFirstAtTheBeginning(":")
                                        .RemoveFirstAtTheEnd("m");
            }
            myAd.Area = area.ToNullableDecimal();
            int priceNum;
            float areaNum;
            if (SearchData.EstateType != "room" && innerDom["div.dane"].Text().Length > 0)
            {
                var nodeValue = innerDom["div.dane"].Find("br")[0].PreviousSibling.NodeValue;
                if (nodeValue == null) myAd.PricePerMeter = null;
                else
                {
                    var pricePerMeter =
                        nodeValue.RemoveFirstAtTheBeginning("(")
                                 .RemoveLastAtTheEnd("pln").Trim();
                    myAd.PricePerMeter = pricePerMeter.ToNullableDecimal();
                }
            }
            else if (int.TryParse(price, out priceNum) && float.TryParse(area, out areaNum))
            {
                myAd.PricePerMeter = Math.Round(priceNum / areaNum, 2).ToString().ToNullableDecimal();
            }
            else
            {
                myAd.PricePerMeter = null;
            }
            if (SearchData.EstateType == "flat" && SearchData.AdvertisementType == "sell")
            {
                var floor = innerDom["h2.szczeg_h2"].Text().RemoveFirstAtTheBeginning("na").RemoveFirstAtTheEnd("pi").Trim();
                myAd.Floor = floor.Contains("parter") ? 0 : StringUtils.DecodeRomanNumber(floor);
            }
            else if (SearchData.EstateType == "flat" && SearchData.AdvertisementType == "rent")
            {
                if (innerDom["title"].Text().Contains("parter")) myAd.Floor = 0;
                else
                {
                    var titleSplit =
                        innerDom["title"].Text().Split(',');
                    var floor = titleSplit[titleSplit.Length - 1].RemoveFirstAtTheEnd("pi").Trim();
                    myAd.Floor = StringUtils.DecodeRomanNumber(floor);
                }
            }
            else
            {
                myAd.Floor = null;
            }
            var modified = innerDom["div.szczegoly ul li:contains(data ostatniej aktualizacji:)"].Html().Trim();
            if (modified.Contains("<strong>"))
                modified = modified.Substring(modified.IndexOf("</strong>") + 9).Trim();
            myAd.Modified = String.IsNullOrEmpty(modified) ? null : DateTime.ParseExact(modified, "yyyy-MM-dd HH:mm:ss", null).ToShortDateString().ToNullableDateTime();
        }
    }
}